home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / procssng / alv.sun / alv.lha / src / glass.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-08  |  15.7 KB  |  683 lines

  1. /*
  2.  *  Magnifying glass        (for Sun-3 workstations)
  3.  *
  4.  *  Copyright 1986, 1987 by Scott Schwartz
  5.  *  This program may be copied with the provision that this copyright 
  6.  *  message remains, and that further distribution of this code and it's 
  7.  *  derivatives is not subject to additional restrictions.
  8.  * 
  9.  *  Lots of changes, but no Copyright, by Mark Weiser.
  10.  * 
  11.  *  compile with -lsuntool -lsunwindow -lpixrect
  12.  *
  13.  *  vi: set ts=8
  14.  *
  15.  *  revision history:
  16.  *  10 Nov 86    initial coding                 Scott Schwartz 
  17.  *
  18.  *  version 1.0        25 Nov 86
  19.  *    modified to draw big pixels with raster-ops        ses
  20.  *
  21.  *  version 1.1        27 Jan 87
  22.  *    does magnification in memory,                 ses
  23.  *    to avoid screen access
  24.  *
  25.  *  version 1.2        27 Jan 87
  26.  *    flood destination with white,                 ses/af
  27.  *      then draw only black spots
  28.  *
  29.  *  version 2.0        15 Apr 87                mark weiser
  30.  *    vastly faster magnification algorithm using only 2k blits
  31.  *    instead of k**2 (where k is the height or width of the final).
  32.  *    Also added a panel for friendliness, and stopped using *all* the cpu!
  33.  *
  34.  *  version 2.1        17 Apr 87                mark weiser
  35.  *    added locking.
  36.  *
  37.  *  version 2.2        20 Apr 87                mark weiser
  38.  *    added changes for color suns (not tested here).
  39.  *
  40.  *  version 2.3        6 June 87                Ed Falk
  41.  *    general clean-up, made to work with color suns.
  42.  *    minor performance improvements.  Locking around the
  43.  *    initial screen read in order to get garbage out of
  44.  *    image.
  45.  */
  46.  
  47. #include <stdio.h>
  48. #include <fcntl.h>
  49. #include <sys/ioctl.h>
  50. #include <suntool/sunview.h>
  51. #include <suntool/canvas.h>
  52. #include <suntool/panel.h>
  53. #include <suntool/textsw.h>
  54. #include <pixrect/pixrect_hs.h>
  55.  
  56. /* I HATE these macros    -mdw */
  57. #undef min
  58. #undef max
  59.  
  60.  
  61. /* useful macros */
  62. #define ERROR(msg)  { fprintf(stderr, "%s: %s\n", argv[0], msg); exit(1); }
  63.  
  64. /* forward declarations */
  65. xtern    char *getenv(), *sprintf();
  66. xtern    Notify_error    notify_dispatch();
  67. tatic    Notify_value    notice_destroy_event();
  68. tatic    Notify_value    update_value_proc();
  69. tatic    Notify_value    update_mag_proc();
  70. tatic    void    pw_mag();
  71. tatic    void    view();
  72. tatic    void    update();
  73. tatic    void    glass_time_proc();
  74. tatic    void    lock_proc(), unlock_proc();
  75. tatic    void    repaint_proc(), resize_proc() ;
  76.  
  77. /* constants */
  78. tatic char frame_label[] = "Magnifying Glass 2.3";
  79. tatic short icon_image[] = {
  80. #include "../images/icons/glass.icon"
  81. };
  82. EFINE_ICON_FROM_IMAGE(icon, icon_image);
  83. #define NILPR ((struct pixrect *)0)
  84. #define MAX_MAG 32
  85.  
  86. /* global vars */
  87. tatic struct pixrect    *tmpsrc; /* working space, to avoid screen access */ 
  88. tatic struct pixrect    *tmpdst;
  89. tatic int done = 0;
  90. truct pixrect *srcpr; /* the source pixrect, i.e. the whole screen */
  91. nt rootfd;  /* file descriptor for root window, for cursor location */
  92.  
  93. /* things to draw on */
  94. anel panel;
  95. Frame frame;    /* the actual window frame */
  96. anvas canvas;    /* our particular canvas, filling the frame */
  97.  
  98. nt mag = 1;            /* magnification in output window */
  99. nt delay = 1000;
  100. nt locked = 0;
  101. nt locked_x, locked_y;
  102. anel_item time_left_item;
  103.  
  104. /* 
  105.  *  main routine
  106.  */
  107. ain(argc,argv)
  108. nt argc;
  109. har **argv;
  110. {
  111.     char    *parent;    /* name of the parent window, usually win0 */
  112.     char    *magstr = "x99999";    /* allocate space for actual string */
  113.     int    retcode;
  114.     Pixwin    *canvas_pw ;
  115.     int    w, h ;
  116.  
  117.     /* create output window */
  118.     frame = window_create(NULL, FRAME, 
  119.         FRAME_LABEL, frame_label,
  120.         FRAME_ICON, &icon,
  121.         FRAME_ARGC_PTR_ARGV, &argc, argv,
  122.         /* WIN_ERROR_MSG, "Can't create Frame", */
  123.         0);
  124.  
  125.     panel = window_create(frame, PANEL, 0);
  126.     (void) panel_create_item(panel, PANEL_SLIDER,
  127.         PANEL_LABEL_STRING, "Mag:",
  128.         PANEL_VALUE, mag,
  129.         PANEL_MIN_VALUE, 1,
  130.         PANEL_MAX_VALUE, MAX_MAG,
  131.         PANEL_SHOW_RANGE, FALSE,
  132.         PANEL_SHOW_VALUE, TRUE,
  133.         PANEL_SLIDER_WIDTH, 100,
  134.         PANEL_NOTIFY_PROC, update_mag_proc,
  135.         PANEL_CLIENT_DATA, &mag,
  136.         0);
  137.     (void) panel_create_item(panel, PANEL_SLIDER,
  138.         PANEL_LABEL_STRING, "Delay:",
  139.         PANEL_VALUE, 10000,
  140.         PANEL_MIN_VALUE, 1000,
  141.         PANEL_MAX_VALUE, 999999,
  142.         PANEL_SHOW_RANGE, FALSE,
  143.         PANEL_SHOW_VALUE, FALSE,
  144.         PANEL_SLIDER_WIDTH, 100,
  145.         PANEL_NOTIFY_PROC, update_value_proc,
  146.         PANEL_CLIENT_DATA, &delay,
  147.         PANEL_ITEM_X, ATTR_COL(0),
  148.         PANEL_ITEM_Y, ATTR_ROW(1),
  149.         0);
  150.  
  151.     (void) panel_create_item(panel, PANEL_BUTTON,
  152.         PANEL_LABEL_IMAGE, panel_button_image(panel, "Lock", 6, 0),
  153.         PANEL_NOTIFY_PROC, lock_proc,
  154.         PANEL_ITEM_X, ATTR_COL(0),
  155.         PANEL_ITEM_Y, ATTR_ROW(2),
  156.         0);
  157.  
  158.     (void) panel_create_item(panel, PANEL_BUTTON,
  159.         PANEL_LABEL_IMAGE, panel_button_image(panel, "Unlock", 6, 0),
  160.         PANEL_NOTIFY_PROC, unlock_proc,
  161.         0);
  162.  
  163.     time_left_item = panel_create_item(panel, PANEL_SLIDER,
  164.         PANEL_LABEL_STRING, "Time Left:",
  165.         PANEL_VALUE, 10,
  166.         PANEL_MIN_VALUE, 0,
  167.         PANEL_MAX_VALUE, 10,
  168.         PANEL_SHOW_RANGE, FALSE,
  169.         PANEL_SHOW_VALUE, FALSE,
  170.         PANEL_SLIDER_WIDTH, 100,
  171.         PANEL_ITEM_X, ATTR_COL(0),
  172.         PANEL_ITEM_Y, ATTR_ROW(2),
  173.         PANEL_SHOW_ITEM, FALSE,
  174.         0);
  175.     window_fit_height(panel);
  176.  
  177.     /* gather data on output pixwin */
  178.     canvas = window_create(frame, CANVAS,
  179.         WIN_HEIGHT, 200,
  180.         WIN_WIDTH, 200,
  181.         CANVAS_RESIZE_PROC, resize_proc,
  182.         CANVAS_REPAINT_PROC, repaint_proc,
  183.         CANVAS_RETAINED, FALSE,
  184.         WIN_IGNORE_PICK_EVENTS, MS_RIGHT,
  185.             MS_MIDDLE, MS_LEFT, 0,
  186.         0);
  187.  
  188.     window_fit(frame);
  189.  
  190.     canvas_pw = canvas_pixwin(canvas);
  191.  
  192.     /* open rootwindow */
  193.     parent = getenv("WINDOW_PARENT");
  194.     if (parent==NULL) 
  195.         ERROR("can't get WINDOW_PARENT from environment.")
  196.     rootfd = open(parent, O_RDONLY, 0);
  197.     if (rootfd<0)
  198.         perror(argv[0]); 
  199.  
  200.     /* open frame buffer */
  201.     srcpr = canvas_pw->pw_pixrect ;
  202.  
  203.     /* set color table from frame buffer's color table */
  204.  
  205.     {
  206.       unsigned char    red[256], green[256], blue[256] ;
  207.       pr_getcolormap(srcpr, 0, 256, red, green, blue) ;
  208.       pw_setcmsname(canvas_pw, "glass") ;
  209.       pw_putcolormap(canvas_pw, 0, 256, red, green, blue) ;
  210.     }
  211.  
  212.     /* handle arguments */        
  213.     if (argc > 1) {
  214.         retcode = sscanf(argv[1], "%d", &mag);
  215.         if (retcode <= 0) 
  216.             ERROR("\
  217. roblem evaluating arguments\n\
  218. sage: glass magnification [suntools-options]");
  219.         mag = (mag > MAX_MAG) ? MAX_MAG : mag;
  220.     }
  221.  
  222.     /* allocate static pixrects */
  223.     w = (int) window_get(canvas, WIN_WIDTH) ;
  224.     h = (int) window_get(canvas, WIN_HEIGHT) ;
  225.     tmpdst = mem_create(w, h, srcpr->pr_depth);
  226.  
  227.     /* set up an interposed event handler so we know when to quit */
  228.     (void)notify_interpose_destroy_func(frame, notice_destroy_event);
  229.     
  230.     /* start us in a second */
  231.     do_with_delay(glass_time_proc, 1, 0);
  232.  
  233.     /* copy input to output forever */
  234.     window_main_loop(frame);
  235.     exit(0);
  236. }
  237.  
  238.  
  239.  
  240. tatic    void
  241. esize_proc(canvas, width, height)
  242.     Canvas    canvas ;
  243.     int    width, height ;
  244. {
  245.     int    w,h ;
  246.  
  247.     /* destroy and re-allocate temporary pixrects */
  248.  
  249.     pr_destroy(tmpdst) ;
  250.  
  251.     w = width ;
  252.     h = height ;
  253.     tmpdst = mem_create(w, h, srcpr->pr_depth);
  254. }
  255.  
  256.  
  257.  
  258.  
  259. tatic    void
  260. epaint_proc(canvas, pw, repaint_area)
  261.     Canvas        canvas ;
  262.     Pixwin        *pw ;
  263.     Rectlist    *repaint_area ;
  264. {
  265.     view(rootfd, srcpr, canvas, mag);
  266. }
  267.  
  268.  
  269.  
  270.  
  271. /*
  272.  * Thing to do at intervals.
  273.  */
  274. tatic    void
  275. lass_time_proc()
  276. {
  277.     if (done) return;
  278.     if (window_get(frame, FRAME_CLOSED)) {
  279.         do_with_delay(glass_time_proc, 2, 0);
  280.     } else {
  281.         view(rootfd, srcpr, canvas, mag);
  282.         do_with_delay(glass_time_proc, 0, delay);
  283.     }
  284. }
  285.  
  286. /*
  287.  * view does the work of displaying the (possibly) magnified image
  288.  * at the location indicated by rootfd (mouse). view copies srcpr to dstpw.
  289.  */
  290. tatic    void
  291. iew(rootfd, srcpr, canvas, mag)
  292.     int rootfd;        /* root window, for mouse data */    
  293.     struct pixrect *srcpr;        /* screen source pixrect */
  294.     Canvas canvas;
  295.     int mag;
  296. {
  297.     /* constants */
  298.     int maxy = (srcpr->pr_size.y);
  299.     int maxx = (srcpr->pr_size.x);
  300.     Pixwin *dstpw = canvas_pixwin(canvas);
  301.  
  302.     /* local vars */    
  303.     int x,y;
  304.     int w, h;
  305.  
  306.     /* 
  307.      * read mouse coords from vuid register.  sadly, the sunview
  308.      * programmers guide is not clear on this.  appendix A tells some,
  309.      * but you have to look at <sundev/vuid_event.h> to see what
  310.       * virtual events you can find out about.  luckily, the mouse is
  311.      * one of them.
  312.      */
  313.     if (locked) {
  314.         x = locked_x;
  315.         y = locked_y;
  316.     } else {
  317.         x = win_get_vuid_value(rootfd, LOC_X_ABSOLUTE);
  318.         y = win_get_vuid_value(rootfd, LOC_Y_ABSOLUTE);
  319.     }
  320.  
  321.     /* 
  322.      * find out how big our drawing surface is.
  323.      */
  324.     w = (int) window_get(canvas, CANVAS_WIDTH);
  325.     h = (int) window_get(canvas, CANVAS_HEIGHT);
  326.  
  327.     /*
  328.      * draw on it.
  329.      */
  330.     if (mag<=1) {
  331.         x = min(maxx-w, max(x-w, 0));
  332.         y = min(maxy-h, max(y-h, 0));
  333.         update(dstpw, 0, 0, w, h, PIX_SRC, srcpr, x, y);
  334.     }
  335.     else {
  336.         x = min(maxx-w/mag, max(x-w/mag, 0));
  337.         y = min(maxy-h/mag, max(y-h/mag, 0));
  338.         pw_mag(dstpw, 0, 0, w, h, mag, srcpr, x, y);
  339.     }
  340. }
  341.  
  342. /*
  343.  * pw_mag copies a magnified view of spr to dpw using pixel replication.
  344.  * the arguments are the same as those to the pw_rop library call, except
  345.  * that magnification is passed instead of raster-op.
  346.  */
  347. tatic    void
  348. w_mag(dpw, dx, dy, w, h, mag, spr, sx, sy)
  349.     Pixwin *dpw;    /* destination pixwin */
  350.     int dx, dy;      /* destination x,y */
  351.     int w, h;    /* width and height of block to copy */
  352.     int mag;     /* magnification */
  353.     struct pixrect *spr;    /* source pixrect */
  354.     int sx,sy;    /* location in source to copy from */
  355. {
  356.     /* locals */
  357.     register int    xmax, ymax ;
  358.     register int    x, y, delta, cnt ;
  359.     register int    x0, y0 ;
  360.     Rect    lock_rect ;
  361.  
  362.     /* w,h are maximum output (magnified) dimensions; xmax,ymax are
  363.        maximum input dimensions, rounded up */
  364.  
  365.     xmax = (w+mag-1)/mag ;
  366.     ymax = (h+mag-1)/mag ;
  367.  
  368.     /* make off-screen copy of source */
  369.     /* KLUDGE:  pixrect and pixwin operations will interfere with
  370.        each other, causing garbage to appear in the canvas if
  371.        the cursor is being moved during the pr_rop.  By locking
  372.        something (anything) during the pr_rop, we avoid this problem */
  373.  
  374.     lock_rect.r_left = lock_rect.r_top = 0 ;
  375.     lock_rect.r_width = w ;  lock_rect.r_height = h ;
  376.     pw_lock(dpw, &lock_rect) ;
  377.     pr_rop(tmpdst, 0, 0, xmax, ymax, PIX_SRC|PIX_DONTCLIP, spr, sx, sy);
  378.     pw_unlock(dpw) ;
  379.  
  380.  
  381.     delta = xmax*mag - w ;            /* error term */
  382.     x0 = xmax-1; cnt = mag-delta ;
  383.     for(x = w-1; x>=0; --x)
  384.     {
  385.       pr_rop(tmpdst, x, 0, 1, ymax, PIX_SRC|PIX_DONTCLIP, tmpdst, x0, 0);
  386.       if(--cnt <= 0)
  387.       {
  388.         cnt = mag ;
  389.         --x0 ;
  390.       }
  391.     }
  392.  
  393.     delta = ymax*mag - h ;            /* error term */
  394.     y0 = ymax-1; cnt = mag-delta ;
  395.     for(y = h-1; y>=0; --y)
  396.     {
  397.       pr_rop(tmpdst, 0, y, w, 1, PIX_SRC|PIX_DONTCLIP, tmpdst, 0, y0);
  398.       if(--cnt <= 0)
  399.       {
  400.         cnt = mag ;
  401.         --y0 ;
  402.       }
  403.     }
  404.  
  405.  
  406.     /* draw */
  407.     update(dpw, dx, dy, w, h, PIX_SRC, tmpdst, 0, 0);
  408. }
  409.  
  410. /* for debugging purposes, mostly */
  411. tatic    void
  412. pdate(dpw, dx, dy, w, h, mag, spr, sx, sy)
  413.     Pixwin *dpw;    /* destination pixwin */
  414.     int dx, dy;      /* destination x,y */
  415.     int w, h;    /* width and height of block to copy */
  416.     int mag;     /* magnification */
  417.     struct pixrect *spr;
  418.     /* source pixrect */
  419.     int sx,sy;    /* location in source to copy from */
  420. {
  421. w_rop(dpw, dx, dy, w, h, mag, spr, sx, sy);
  422. }
  423.  
  424.  
  425. /* 
  426.  * a service routine that gets called when the frame is destroyed
  427.  * by someone selecting 'quit'.  this is basically right out of the 
  428.  * manual.
  429.  */
  430. tatic Notify_value
  431. otice_destroy_event(frame, status)
  432.     Frame *frame;
  433.     Destroy_status status;
  434. {
  435.     if (status != DESTROY_CHECKING) {
  436.         done = 1;
  437.     }
  438.     return (notify_next_destroy_func(frame,status));
  439. }
  440.  
  441. /*
  442.  * The routines below I have found enormously handy when dispatching
  443.  * things via the notifier.  Use them in good health, or bad.  I do.
  444.  *        -mark weiser
  445.  */
  446.  
  447. /*
  448.  * Call procedure f in a little while.
  449.  */
  450. o_with_delay(f, secs, usecs)
  451. oid (*f)();
  452. nt secs, usecs;
  453. {
  454.     Notify_value do_the_call();
  455.     struct itimerval timer;
  456.  
  457.     /* Sigh, so much work just to wait a bit before starting up. */
  458.     timer.it_interval.tv_usec = 0;
  459.     timer.it_interval.tv_sec = 0;
  460.     timer.it_value.tv_usec = usecs;
  461.     timer.it_value.tv_sec = secs;
  462.     notify_set_itimer_func(f, do_the_call,
  463.         ITIMER_REAL, &timer, NULL);
  464. }
  465.  
  466. /*
  467.  * Wrapper to make sure procedures from do_with_delay return good values
  468.  * to the notifier.
  469.  */
  470. otify_value
  471. o_the_call(f, which)
  472. oid (*f)();
  473. {
  474.     (*f)();
  475.     return NOTIFY_DONE;
  476. }
  477.  
  478. tatic    Notify_value
  479. pdate_mag_proc(item, value)
  480.     Panel_item    item;
  481.     int        value ;
  482. {
  483.     int    width, height ;
  484.     width = (int) window_get(canvas, WIN_WIDTH) ;
  485.     height = (int) window_get(canvas, WIN_HEIGHT) ;
  486.     mag = value;
  487.     resize_proc(canvas, width, height) ;
  488.     return NOTIFY_DONE;
  489. }
  490.  
  491.  
  492. tatic    Notify_value
  493. pdate_value_proc(item, value)
  494.     Panel_item    item;
  495.     int        value ;
  496. {
  497.     int *ptr;
  498.     ptr = (int *)panel_get(item, PANEL_CLIENT_DATA);
  499.     *ptr = value;
  500.     return NOTIFY_DONE;
  501. }
  502.  
  503. tatic    void
  504. ock_proc(item, event)
  505.     Panel_item;
  506.     Event *event;
  507. {
  508.     extern void do_the_lock();
  509.     popup_msg(frame, event, 
  510.         "After buttoning 'Done' in this window,\n\
  511. ou will have ten (10) seconds to put the\n\
  512. ursor someplace.  At the end of 10 seconds,\n\
  513. lass will be locked into looking at that position.");
  514.     locked = 0;
  515. }
  516.  
  517. tatic    void
  518. nlock_proc()
  519. {
  520.     locked = 0;
  521. }
  522.  
  523. tatic    void
  524. o_the_lock()
  525. {
  526.     static void popup_textsw_done();
  527.     locked_x = win_get_vuid_value(rootfd, LOC_X_ABSOLUTE);
  528.     locked_y = win_get_vuid_value(rootfd, LOC_Y_ABSOLUTE);
  529.     locked = 1;
  530. }
  531.  
  532. /*
  533.  * The stuff below is some standard hacks I have started using,
  534.  * especially in the 'sdi' game.  I have inserted them here for convenience.
  535.  *        -mark weiser
  536.  */
  537.  
  538. tatic Frame popup_frame = NULL;
  539. tatic Textsw popup_text;
  540. tatic Panel popup_panel;
  541. tatic Panel_item popup_msg_item;
  542. tatic void popup_yes_proc(), popup_no_proc(), popup_textsw_done();
  543.  
  544. /*
  545.  * Fake an event, so anyone can popup a message. 
  546.  */
  547. asy_pop(msg)
  548. har *msg;
  549. {
  550.     Event event;
  551.     event_x(&event) = (int)window_get(frame, WIN_X); 
  552.     event_y(&event) = (int)window_get(frame, WIN_Y);
  553.     popup_msg(frame, &event, msg);
  554. }
  555.  
  556. /*
  557.  * Pop up a message inside a textsw.  Since textsw's don't really
  558.  * popup (in SunOS 3.2), just display it and put up a 'done' button
  559.  * to kill it when the user is done.
  560.  * Frame should be the frame in which Event occured.  Msg can
  561.  * contain imbedded newlines.
  562.  */
  563. opup_msg(frame, event, msg)
  564. Frame *frame;
  565. Event *event;
  566. har *msg;
  567. {
  568.     int lines = count_lines(msg);
  569.     if (popup_frame != NULL) {
  570.         /* Can only do one of these at a time. */
  571.         return;
  572.     }
  573.     init_popup_msg(frame, msg, lines);
  574.     textsw_insert(popup_text, msg, strlen(msg));
  575.     window_set(popup_frame, WIN_X, event_x(event),
  576.         WIN_Y, event_y(event),
  577.         WIN_SHOW, TRUE,
  578.         0);
  579. }
  580.  
  581. /*
  582.  * A helper proc to do all the work of window creation for message popups
  583.  */
  584. nit_popup_msg(baseframe, msg, lines)
  585. Frame baseframe;
  586. har *msg;
  587. {
  588.     popup_frame = window_create(baseframe, FRAME,
  589.         WIN_ERROR_MSG, "Can't create window.",
  590.         0);
  591.     popup_panel = window_create(popup_frame, PANEL,
  592.         /* WIN_BELOW, popup_text, */
  593.         WIN_X, ATTR_COL(0),        /* bug workaround, should not be necessary */
  594.         0);
  595.     panel_create_item(popup_panel, PANEL_BUTTON,
  596.         PANEL_LABEL_IMAGE, panel_button_image(popup_panel, "Done", 4, NULL),
  597.         PANEL_NOTIFY_PROC, popup_textsw_done,
  598.         0);
  599.     window_fit(popup_panel);
  600.     popup_text = window_create(popup_frame, TEXTSW,
  601.         WIN_ERROR_MSG, "Can't create window.",
  602.         WIN_ROWS, min(30, lines),
  603.         WIN_COLUMNS, max_line(msg)+3,
  604.         TEXTSW_IGNORE_LIMIT, TEXTSW_INFINITY,
  605.         TEXTSW_CONTENTS, msg,
  606.         TEXTSW_BROWSING, TRUE,
  607.         TEXTSW_DISABLE_LOAD, TRUE,
  608.         TEXTSW_DISABLE_CD, TRUE,
  609.         0);
  610.     window_fit(popup_frame);
  611. }
  612.  
  613. oid
  614. imeout_proc()
  615. {
  616.     int val = (int)panel_get_value(time_left_item);
  617.     if (val > 0) {
  618.         panel_set(time_left_item, PANEL_VALUE, val-1, 0);
  619.         do_with_delay(timeout_proc, 1, 0);
  620.     } else {
  621.         panel_set(time_left_item, PANEL_SHOW_ITEM, FALSE, 0);
  622.         panel_paint(panel, PANEL_CLEAR);
  623.         do_the_lock();
  624.     }
  625. }
  626.  
  627. /* A helper for killing message popups. */
  628. tatic void
  629. opup_textsw_done()
  630. {
  631.     window_set(popup_frame, FRAME_NO_CONFIRM, TRUE, 0);
  632.     window_destroy(popup_frame);
  633.     popup_frame = NULL;
  634.     panel_set(time_left_item, PANEL_SHOW_ITEM, TRUE, PANEL_VALUE, 10, 0);
  635.     do_with_delay(timeout_proc, 1, 0);
  636. }
  637.  
  638. /*
  639.  * Find the size of the longest line in a string of lines separated by newlines
  640.  */
  641. ax_line(s)
  642. har *s;
  643. {
  644.     int max = 0, count = 0;
  645.     while (*s) {
  646.         if (*s++ == '\n') {
  647.             if (count > max)
  648.                 max = count;
  649.             count = 0;
  650.             continue;
  651.         }
  652.         count += 1;
  653.     }
  654.     if (count > max)
  655.         max = count;
  656.     return max;
  657. }
  658.  
  659. /*
  660.  * Count the number of lines in a string of lines separated by newlines.
  661.  */
  662. ount_lines(s)
  663. har *s;
  664. {
  665.     int count = 0;
  666.     while (*s) {
  667.         if (*s++ == '\n')
  668.             count += 1;
  669.     }
  670.     return count+1;
  671. }
  672.  
  673. /* need functions, not macros, because of non-idempotent funcall arguments */
  674. ax(x,y)
  675. {
  676.     return x<y ? y : x;
  677. }
  678.  
  679. in(x,y)
  680. {
  681.     return x<y ? x : y;
  682. }
  683.